PostgreSQL 数据库存储 t_infomask

1 背景知识

本文主要介绍 t_infomask 的数据结构和底层原理。

2 t_infomask 信息

使用 pageinspect 扩展插件函数 heap_page_items ,可以看到 t_infomask 值,这个 t_infomask 是个两字节的值,含有的信息量非常大,每个 bit 都有特定的含义,包括了 锁信息、xmin and xmax 信息、xidfrozen 信息等。以下对这些具体结构的详细说明。

t_infomask 是个16位的值,每bit 都有具体的含义:

 #define HEAP_HASNULL            0x0001    /* has null attribute(s) */

#define HEAP_HASVARWIDTH        0x0002    /* has variable-width attribute(s) */

#define HEAP_HASEXTERNAL        0x0004    /* has external stored attribute(s) */

#define HEAP_HASOID                0x0008    /* has an object-id field */

#define HEAP_XMAX_KEYSHR_LOCK    0x0010    /* xmax is a key-shared locker */

#define HEAP_COMBOCID            0x0020    /* t_cid is a combo cid */

**#define HEAP_XMAX_EXCL_LOCK        0x0040    /* xmax is exclusive locker */**

#define HEAP_XMAX_LOCK_ONLY        0x0080    /* xmax, if valid, is only a locker */

#define HEAP_XMAX_SHR_LOCK    (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)  

#define HEAP_LOCK_MASK    (HEAP_XMAX_SHR_LOCK | HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)

  

#define HEAP_XMIN_COMMITTED        0x0100    /* t_xmin committed */

#define HEAP_XMIN_INVALID        0x0200    /* t_xmin invalid/aborted */

**#define HEAP_XMIN_FROZEN        (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)  --两个位都为1** 

#define HEAP_XMAX_COMMITTED        0x0400    /* t_xmax committed */

#define HEAP_XMAX_INVALID        0x0800    /* t_xmax invalid/aborted */

#define HEAP_XMAX_IS_MULTI        0x1000    /* t_xmax is a MultiXactId */

#define HEAP_UPDATED            0x2000    /* this is UPDATEd version of row */

#define HEAP_MOVED_OFF            0x4000    /* moved to another place by pre-9.0 * VACUUM FULL; kept for binary * upgrade support */

#define HEAP_MOVED_IN            0x8000    /* moved from another place by pre-9.0 * VACUUM FULL; kept for binary  * upgrade support */

#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)

 #define HEAP_XACT_MASK            0xFFF0    /* visibility-related bits */

3 xmin & xmax 状态指示位

3.1 新增记录

CREATE TABLE t01(id integer,name text);  
INSERT INTO t01 values(1,'a');   
SELECT T_INFOMASK FROM heap_page_items(get_raw_page('t1',0)) ;
//屏幕输出:
t_infomask  
------------  
2050

第1次访问之前:2050 转二进制 1000 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_INVALID ,其他黑体部分 0 是没有信息的。读者可能会奇怪,事务不是已提交了吗,HEAP_XMIN_COMMITTED 对应的bit 怎么还是 0 ?

test=# select id,xmin,xmax from t1;  
id    | xmin | xmax  
----+------+------  
1     | 3288 | 0  

  
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;  
t_infomask  
------------  
2306

第1次访问之后:2036转二进制 1001 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_INVALID and HEAP_XMIN_COMMITTED ,变化点是 HEAP_XMIN_COMMITTED 有值了,这也意味着后续读取该记录时,无需通过clog判断事务是否状态。

3.1.1 删除记录

 test=# delete from t1 where id=1;

DELETE 1  
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;  
t_infomask  
------------  
258  
(1 row)

删除记录后,第1次访问之前:258 转二进制 0001 0000 0010,其中黑体部分 1 对应:HEAP_XMIN_COMMITTED 。同样问题,事务已提交,为什么 HEAP_XMAX_INVALID 还是 0 ?

test=# select id,xmin,xmax from t1;  
id    | xmin | xmax  
----+------+------  
(0 rows)  
  
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;  
t_infomask  
------------  
1282  
(1 row)

删除记录后,第1次访问之后:1282 转二进制 0101 0000 0010,其中黑体部分 1 对应:HEAP_XMAX_COMMITTED and HEAP_XMIN_COMMITTED ,变化点是 HEAP_XMAX_COMMITTED 有值了,这也意味着后续读取该记录时,无需通过clog判断事务是否状态。

PS:以上的测试有 HEAP_HASVARWIDTH 标志位,这代表什么意思?实际有时同样测试,却没有 HEAP_HASVARWIDTH 标志位。

4 xmax 锁标志位

会话1:


test=# create table t1(id integer);  
CREATE TABLE  
test=# insert into t1 values(1);  
INSERT 0 1  
test=# begin;  
BEGIN  
test=# select * from t1 where id=1 for update;  
id  
----  
1  
(1 row)  

test=# select id,xmin,xmax from t1;  
id    | xmin | xmax  
----+------+------  
1     | 3296 | **3297**  

会话2:

test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;  
t_infomask  
------------  
448  
(1 row)

448 转二进制 0001 1100 0000,黑体部分 HEAP_XMAX_EXCL_LOCK   and HEAP_XMAX_LOCK_ONLY  ,也就是说这里的xmax 只是表示在该记录上有exclusive lock

5 xidfrozen 标志位

test=# create table t1(id integer);  
CREATE TABLE  
test=# insert into t1 values(1);  
INSERT 0 1  
test=# select * from t1;  
id  
----  
1  
(1 row)  
  
test=# select t_infomask from heap_page_items( get_raw_page('t1',0) ) ;  
t_infomask  
------------  
2304  
(1 row)  
  
test=# vacuum freeze t1;  
VACUUM  
test=# select t_infomask from heap_page_items(get_raw_page('t1',0)) ;  
t_infomask  
------------  
2816  
(1 row)  

test=# select id, xmin,xmax from t1;  
id | xmin | xmax  
----+------+------  
1 | 3300 | 0  
(1 row)

2816 转二进制 1011 0000 0000,黑体部分三个1 分别表示:HEAP_XMAX_INVALID 、HEAP_XMIN_INVALID、HEAP_XMIN_COMMITTED,其中 11 表示HEAP_XMIN_FROZEN ,也就是 xidfrozen。